#pragma once

#include "../repo/src/include/root/rpc_root.h"
#include "../util/box_std_allocator.hh"
#include "../util/object_pool.hh"
#include "../util/timer_wheel.hh"
#include <memory>
#include <unordered_map>

namespace kratos {
namespace service {

class ServiceBox;

class TimerImpl : public TimerBase {
  unique_pool_ptr<util::TimerWheel> timer_wheel_{nullptr};
  struct TimerInfo {
    TimerFunc func;
    std::uint64_t user_data{0};
    util::TimerID wheel_handle;
  };
  using TimerInfoMap =
      std::unordered_map<
          std::uint64_t,
          TimerInfo,
          std::hash<std::uint64_t>,
          std::equal_to<std::uint64_t>,
          Allocator<
            std::pair<const std::uint64_t, TimerInfo>>
          >;
  TimerInfoMap timer_info_map_;
  std::uint64_t internal_id_{1};
  ServiceBox* box_{nullptr};

public:
  /// ctor
  TimerImpl(ServiceBox *box);
  /// dtor
  virtual ~TimerImpl();
  /// Start a timer
  /// @param timer_func timer callback
  /// @param duration timeout duration
  /// @param user_data user data
  /// @return timer handle
  virtual TimerHandle addTimerOnce(TimerFunc timer_func, std::time_t duration,
                                   std::uint64_t user_data) override;
  /// Start a loop timer, reserved
  /// @param timer_func timer callback
  /// @param duration timeout duration
  /// @param user_data user data
  /// @return timer handle
  virtual TimerHandle addTimer(TimerFunc timer_func, std::time_t duration,
                               std::uint64_t user_data) override;
  /// Cancel a timer, reserved
  virtual void cancelTimer(TimerHandle handle);
  /// Returns a expired timer
  /// @param now current timestamp in millionsecond
  virtual TimerHandle runOnce(std::time_t now = 0) override;
  /// Clear all timer
  virtual void clear() override;
};

class TimerFactoryImpl : public TimerFactory {
  ServiceBox *box_{nullptr};

 public:
  TimerFactoryImpl(ServiceBox * box);
  virtual ~TimerFactoryImpl();
  virtual TimerBase *create() override;
  virtual void destory(TimerBase *timer_base) override;
};

} // namespace service
} // namespace kratos
